import { paginationOptsValidator } from 'convex/server';
import { ConvexError, v } from 'convex/values';

import { mutation, query } from './_generated/server';

export const get = query({
  args: {
    paginationOpts: paginationOptsValidator,
    search: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    const user = await ctx.auth.getUserIdentity();
    if (!user) {
      throw new ConvexError('Not authenticated');
    }

    const organizationId = (user.organization_id ?? undefined) as string | undefined;

    const { search } = args;

    if (search && organizationId) {
      return await ctx.db
        .query('documents')
        .withSearchIndex('search_title', (q) => q.search('title', search).eq('organizationId', organizationId))
        .paginate(args.paginationOpts);
    }

    if (organizationId) {
      return await ctx.db
        .query('documents')
        .withIndex('by_organization_id', (q) => q.eq('organizationId', organizationId))
        .paginate(args.paginationOpts);
    }

    if (search) {
      return await ctx.db
        .query('documents')
        .withSearchIndex('search_title', (q) => q.search('title', search).eq('ownerId', user.subject))
        .paginate(args.paginationOpts);
    }

    return await ctx.db
      .query('documents')
      .withIndex('by_owner_id', (q) => q.eq('ownerId', user.subject))
      .paginate(args.paginationOpts);
  },
});

export const create = mutation({
  args: { title: v.optional(v.string()), initialContent: v.optional(v.string()) },
  handler: async (ctx, args) => {
    const user = await ctx.auth.getUserIdentity();
    if (!user) {
      throw new Error('Not authenticated');
    }

    const organizationId = (user.organization_id ?? undefined) as string | undefined;

    return await ctx.db.insert('documents', {
      title: args.title ?? 'Untitled document',
      ownerId: user.subject,
      organizationId,
      initialContent: args.initialContent ?? '',
    });
  },
});

export const removeById = mutation({
  args: {
    id: v.id('documents'),
  },
  handler: async (ctx, args) => {
    const user = await ctx.auth.getUserIdentity();
    if (!user) {
      throw new Error('Not authenticated');
    }

    const document = await ctx.db.get(args.id);
    if (!document) {
      throw new Error('Document Not Found');
    }

    const organizationId = (user.organization_id ?? undefined) as string | undefined;

    const isOwner = document.ownerId === user.subject;
    const isOrganizationMember = document.organizationId === organizationId;
    if (!isOwner && !isOrganizationMember) {
      throw new Error('Not authorized');
    }

    return await ctx.db.delete(args.id);
  },
});

export const updateById = mutation({
  args: {
    id: v.id('documents'),
    title: v.string(),
  },
  handler: async (ctx, args) => {
    const user = await ctx.auth.getUserIdentity();
    if (!user) {
      throw new Error('Not authenticated');
    }

    const organizationId = (user.organization_id ?? undefined) as string | undefined;

    const document = await ctx.db.get(args.id);
    if (!document) {
      throw new Error('Document Not Found');
    }

    const isOwner = document.ownerId === user.subject;
    const isOrganizationMember = document.organizationId === organizationId;
    if (!isOwner && !isOrganizationMember) {
      throw new Error('Not authorized');
    }

    return await ctx.db.patch(args.id, { title: args.title });
  },
});
